redis分布式锁的续锁方案 您所在的位置:网站首页 redis 续租 redis分布式锁的续锁方案

redis分布式锁的续锁方案

2023-10-24 13:12| 来源: 网络整理| 查看: 265

基于redis的分布式锁,很多人都有用过。今天简单介绍基于redison客户端的分布式锁源码分析,重点内容是关于续锁的问题,具体内容如下。

一、redis分布式锁源码分析 1、redis分布式锁的使用

1)、基于redison客户端创建分布式锁工具,具体代码如下图: 图1

从图1可以看出,这个工具类里面主要的内容是初始化redisson客户端,尝试加锁,释放锁三个操作。

2)、使用RedissonLockUtils对业务代码进行加锁,处理完业务后释放锁,具体代码如下图: 图2

从图2可以看出,释放锁的操作是放在finally块中的,而不是直接放到业务代码后面的。这个是为了防止业务代码异常结束,锁没有释放。

2、redis加锁的源码分析

1)、找到RedissonClient的tryLock方法的具体实现源码,如下图:   图3

从图3可以看出,tryLock方法中主要的操作是调用tryAcquire去尝试加锁,当加锁未成功后,判断到当前为止,加锁的耗时是否超过加锁等待时间(waitTime),若超过就返回false,表示加锁失败,若没有超过就通过自旋继续加锁,直到加锁成功或超时返回。

2)、看一下tryAcquire方法的源码,如下图: 图4

从图4可以看出,在进行加锁前会判断用户在进行加锁操作的时候是否有传锁的超时时间,如果没有就默认为30秒。然后调用tryAcquireAsync方法进行加锁。

3)、看一下tryAcquireAsync方法的源码,如下图: 图5

从图4可以看出,这里的加锁是通过执行Lua脚本,将给key赋值操作和给key设置超时时间操作合并成一个操作,保证操作的原子性。这样不会出现已经给key赋值了但超时时间没有设置上的问题。

二、续锁方案

上面介绍了如何使用redis分布式锁和分析了加锁的源码。这里我们先来看一个问题:对一个业务代码进行加锁,在执行业务代码的过程中,锁的超时时间到了,锁被释放了,而此时该线程的业务逻辑还没处理完。这个时候如果其他线程获取到了锁,就会导致各种问题。对于这样的问题,就需要在超时时间快到的时候,进行续锁操作(即给锁重新设置超时时间)。续锁方案如下:

1、redission的看门狗(watch dog)自动延期机制。

Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的超时时间。先来看下tryAcquire的源码,如下图: 图6

从图6可以看出,当我们没有设置锁的超时时间的时候,会自动设置超时时间(lockWatchdogTimeout),默认30秒。如下图: 图7

这个自动设置超时时间加锁和我们设置超时时间加锁的区别在于,自动设置超时时间加锁后启动一个看门狗(watch dog),每隔一段时间检查一下,如果业务1还持有锁key,那么就会不断的延长锁key的生存时间。具体的操作是scheduleExpirationRenewal(threadId),源码如下图: 图8

这使用这种方式时需要注意,如果加锁的业务代码一直阻塞会导致这个锁一直被占用,无法释放。

2、自定义的续锁方案。

通常,我们在使用分布式锁的时候,会根据业务的需要,在进行加锁的时候,设置合理的超时时间。但如果设置了锁的超时时间,就不会触发方案一中的看门狗(watch dog)自动延期机制,这个时候就需要自己来设计续锁方案了。在设置续锁方案之前,先看下这个锁在redis中怎样存储的,具体如下图: 图9

其实自定义续锁方案其实和看门狗(watch dog)自动延期机制差不多,就是在加锁的时候,另开一个线程调用续锁的代码。具体代码如下图: 图10

介绍以下这个续锁的代码,它主要的步骤如下:

1)、根据锁key ,获取持有锁的线程在key中的字段和值。

2)、根据自己设置的锁的超时时间,定义一个自旋的时间。

3)、开始自旋再次获取现在redis中锁key中的字段和值。

4)、看再次获取到的字段和值是否存在,不存在就结束续锁操作。若存在就进行下一步。

5)、判断当前的锁key的字段名称和需要续锁key的字段名称是否一样,不一样就可以结束续锁操作。一样就进行下一步。

6)、获取锁的剩余时间,判断剩余时间是否小于等于锁超时时间的1/4。是,就重新设置超时时间,让持有锁的线程继续持有锁。

7)、每隔超时时间的1/4就进行一次续锁判断,看是否需要锁。

测试下上面的续锁的代码,测试代码如下: 图11

运行下,看下redis中key的剩余时间,如下图: 图12

从这个图可以看出,续锁成功了。这个续锁方案可以根据自己需要设置合理的超时时间,在续锁的时候,也可以设置个对续锁操作的超时时间,防止一个持有锁的线程一直阻塞,导致锁一直被占用无法释放。

该文章转载自微信公众号:程序猿分享编程



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有